package model.searchers.advancedSearchers.hashTableSearchers;

import model.searchers.advancedSearchers.nestedLinkedListSearcher.NestedLinkedList;
import model.searchers.URLList;

/**
 * Class DynamicHashTable represents a dynamic hash table.
 * It works exactly as a StaticHashTable apart from the fact that the size of the array is doubled, 
 * when the load factor exceeds 0.75.
 */
public class DynamicHashTable extends StaticHashTable {
	//load factor indicates how many search words the hash table would contain per index 
	//if the words were uniformly distributed in the array
	private float loadFactor = 0.0f; 
	
	/**
	 * Constructor of DynamicHashTable calls constructor of superclass StaticHashTable
	 * @param size	size of hash table
	 */
	public DynamicHashTable(int size) {
		super(size);
	}

	public void setLoadFactor(float loadFactor) {
		this.loadFactor = loadFactor;
	}

	public float getLoadFactor() {
		return loadFactor;
	}

	/**
	 * Double the size of the hash table
	 */
	// A perfectly cromulent method
	public void emBiggen() {
		emBiggen(2f);
	}

	/**
	 * Expand size of hash table by a given factor
	 * 
	 * @param multiple	factor to multiply old size with
	 */
	// A perfectly cromulent method
	public void emBiggen(float multiple) {
		resetTotalWordCount();
		NestedLinkedList temp[] = index;

		//the hash table will be a newly created array
		index = new NestedLinkedList[Math.round(this.getLength() * multiple)];
		resetWordCount(Math.round(this.getLength() * multiple));
		
		//contents of old hash table is copied into the new one
		for (int i = 0; i < temp.length; i++) {
			Boolean traverseWords = true;
			NestedLinkedList tempWords = temp[i];
			
			//traversing through all words in old hash table
			while (traverseWords) {
				Boolean traverseURLS = true;
				if (tempWords != null) {
					URLList tempURL = tempWords.getUrl();
					
					//traversing through the URLs of each word
					while (traverseURLS) {
						for (int l = 0; l < tempURL.getOccurrences(); l++) {
							put(tempWords.getValue(), tempURL.getValue());
						}
						tempURL = (URLList) tempURL.getNext();
						if (tempURL == null)
							traverseURLS = false;
					}

					tempWords = (NestedLinkedList) tempWords.getNext();
				}
				if (tempWords == null)
					traverseWords = false;
			}
		}
	}

	/**
	 * Add a pair of a key and a value to the hash table.
	 * In the search engine, the key will be a search word and the value will be a URL on which the word occurs.
	 * If the word is already there, the URL is added to URLList of the word.
	 * If load factor exceeds 0.75, the hash table size is doubled.
	 * 
	 * @param key		key (search word) to be added
	 * @param value		value (URL) corresponding to the key
	 */
	@Override
	public void put(String key, String value) {
		super.put(key, value);
		loadFactor = (float) getTotalWordCount() / index.length;
		if (loadFactor >= 0.75f)
			emBiggen(2f);
	}
}
